package com.icesoft.core.dao.base;

import com.icesoft.core.dao.criteria.SelectBuilder;
import com.icesoft.core.dao.suppose.HqlQuerySuppose;
import com.icesoft.core.dao.suppose.IDaoInterceptor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@SuppressWarnings("unchecked")
abstract class EntityManagerDao {
    @Getter
    private List<IDaoInterceptor> daoInterceptors;
    private HqlQuerySuppose hqlQuerySuppose;

    EntityManagerDao(HqlQuerySuppose hqlQuerySuppose) {
        this.hqlQuerySuppose = hqlQuerySuppose;
        this.daoInterceptors = new ArrayList<>();
    }

    public EntityManager getEntityManager() {
        return hqlQuerySuppose.getEntityManager();
    }

    public Query createQuery(String hql) {
        return hqlQuerySuppose.createQuery(hql);
    }

    public <D> List<D> findList(SelectBuilder selectBuilder) {
        if(!selectBuilder.getFromBuilder().isSkipFilter()){
            selectBuilder = selectBuilder.clone();
            for (IDaoInterceptor interceptor : daoInterceptors) {
                interceptor.onQuery(selectBuilder);
            }
        }
        return (List<D>) hqlQuerySuppose.findList(selectBuilder);
    }

    public <D> D findSingle(SelectBuilder selectBuilder) {
        if(!selectBuilder.getFromBuilder().isSkipFilter()){
            selectBuilder = selectBuilder.clone();
            for (IDaoInterceptor interceptor : daoInterceptors) {
                interceptor.onQuery(selectBuilder);
            }
        }
        return (D) hqlQuerySuppose.findSingle(selectBuilder);
    }

    public <T extends Model> List<T> findAll(Class<T> clazz) {
        return hqlQuerySuppose.findAll(clazz);
    }

    public <T extends Model> int countAll(Class<T> clazz) {
        return hqlQuerySuppose.countAll(clazz);
    }

    @Transactional
    public <T extends Model> void create(T model) {
        for (IDaoInterceptor interceptor : daoInterceptors) {
            interceptor.onCreate(model);
        }
        if (log.isTraceEnabled()) {
            log.trace("新建数据：{}", model);
        }
        getEntityManager().persist(model);
    }

    @Transactional
    public <T extends Model> void update(T model) {
        for (IDaoInterceptor interceptor : daoInterceptors) {
            interceptor.onUpdate(model);
        }
        if (log.isTraceEnabled()) {
            log.trace("修改数据：{}", model);
        }
        getEntityManager().merge(model);
    }

    @Transactional
    public <T extends Model> void delete(T model) {
        //必须重新赋值，从游离态变成Managed
        for (IDaoInterceptor interceptor : daoInterceptors) {
            interceptor.onDelete(model);
        }
        model = getEntityManager().merge(model);
        if (log.isTraceEnabled()) {
            log.trace("删除{}，数据：{}", model.getClass().getSimpleName(), model);
        }
        getEntityManager().remove(model);
    }

    public <T extends Model> T load(Class<T> modelClass, Object modelId) {
        T model = getEntityManager().find(modelClass, modelId);
        if (log.isTraceEnabled()) {
            log.trace("load {} id={} : {}", modelClass.getSimpleName(), modelId, model);
        }
        if (model == null) {
            log.warn("未找到id为{}的{}", modelId, modelClass.getName());
        } else {
            for (IDaoInterceptor interceptor : daoInterceptors) {
                interceptor.onLoad(model);
            }
        }

        return model;
    }
}
